﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace SEO.Utility
{
    /// <summary>
    /// 版权所有: 版权所有(C) 2011，Adin Lee
    /// 内容摘要: 超时线程控制
    /// 完成日期：2011年8月17日
    /// 版    本：V1.0 
    /// 作    者：Adin
    /// </summary>
    public class OverTimeCntrol
    {
        public delegate void Delegate();

        /// <summary>
        /// 执行指定的方法,如果在指定的时间之内没有完成,则中止
        /// </summary>
        /// <param name="func">任务过程</param>
        /// <param name="timeSpan">超时时间</param>
        /// <param name="timeoutCallback">如果超时，则调用该方法</param>
        /// <returns>是否正确执行完毕</returns>
        public static bool CallFuncThread(Delegate func, TimeSpan timeSpan, Delegate timeoutCallback)
        {
            if (func == null)
                throw new ArgumentNullException("func");

            ManualResetEvent resetEvent = new ManualResetEvent(false);
            ManualResetEvent waitThreadEvent = new ManualResetEvent(false);

            Exception error = null;
            Thread thread = null;

            // 将任务加到线程当中
            ThreadPool.QueueUserWorkItem(delegate
            {

                thread = Thread.CurrentThread;
                try { func(); }
                catch (ThreadAbortException) { }
                catch (Exception ex) { error = ex; }

                resetEvent.Set();
                waitThreadEvent.WaitOne();  // 每次线程执行结束都等待后续的处理逻辑
            });

            try
            {
                bool result = resetEvent.WaitOne(timeSpan, false);  // 等待任务的结束

                if (error != null)  // 说明在执行过程中出现异常，直接抛出异常
                    throw error;

                if (!result)
                {
                    if (thread != null)
                    {
                        thread.Abort();  // 此时可以确保该线程没有开始运行新的任务
                        waitThreadEvent.Set();
                    }

                    if (timeoutCallback != null)
                        timeoutCallback();
                }

                return result;
            }
            finally
            {
                waitThreadEvent.Set();  // 最后确保释放线程池线程
            }
        }
    }
}
